/* eslint-disable @typescript-eslint/no-unused-vars */
const G0 = 9.80665

const HPtrop = 11000.0
const BetaT = -0.0065
const R = 287.05287
const K = 1.4

/// /ISA
//
const ISAP0 = 101325.0
const ISAT0 = 288.15
const ISATTrop = ISAT0 + BetaT * HPtrop
const ISARho0 = 1.225
const ISAA0 = 340.294

//
/// /magic number
const u = (K - 1) / K
const u1 = K / (K - 1)
const u2 = -1 / (K - 1)
const u3 = (K - 1) / 2
const f1 = (BetaT * R) / G0
const f2 = (K * BetaT * R) / G0 / 2.0
const f3 = -G0 / BetaT / R
const kr = K * R
const tDeltaTrop = HPtrop * BetaT
const g0dR = G0 / R
const ISAPTrop = Math.pow(ISAP0 * (ISATTrop / ISAT0), f3)

export function transitionAltitude(vCAS: number, mach: number): number {
  let tmp1 = 1 + (u3 * vCAS * vCAS) / ISAA0 / ISAA0
  tmp1 = Math.pow(tmp1, u1) - 1
  let tmp2 = 1 + u3 * mach * mach
  tmp2 = Math.pow(tmp2, u1) - 1
  const theta = Math.pow(tmp1 / tmp2, -f1)
  return (1000 / 6.5) * (ISAT0 * (1 - theta))
}

export class AirData {
  public readonly altitude: number
  public readonly pressure: number
  public readonly temperature: number
  public readonly density: number
  public readonly soundSpeed: number

  constructor(alt: number, p: number, t: number, d: number, s: number) {
    this.altitude = alt
    this.pressure = p
    this.temperature = t
    this.density = d
    this.soundSpeed = s
  }

  public TAS2Mach(tas: number): number {
    return _TAS2Mach(tas, this.soundSpeed)
  }

  public mach2TAS(mach: number): number {
    return _mach2TAS(mach, this.soundSpeed)
  }

  public TAS2CAS(tas: number): number {
    return _TAS2CAS(tas, this.pressure, this.density)
  }

  public CAS2TAS(cas: number): number {
    return _CAS2TAS(cas, this.pressure, this.density)
  }

  public mach2CAS(mach: number): number {
    return this.TAS2CAS(this.mach2TAS(mach))
  }

  public CAS2Mach(cas: number): number {
    return this.TAS2Mach(this.CAS2TAS(cas))
  }
}

export class AtmosphereModel {
  readonly deltaT: number
  readonly deltaP: number
  private pMSL: number

  private hpMSL: number
  private t0: number
  private tISAMSL: number
  private tTrop: number
  private pTrop: number

  constructor(deltaT: number, deltaP: number) {
    this.deltaP = deltaP
    this.deltaT = deltaT
    this.pMSL = deltaP + ISAP0

    this.hpMSL = ISAT0 + BetaT * (Math.pow(this.pMSL / ISAP0, f1) - 1)
    this.t0 = ISAT0 + deltaT
    this.tISAMSL = ISAT0 + BetaT * this.hpMSL
    this.tTrop = this.t0 + BetaT * HPtrop
    this.pTrop = ISAP0 * Math.pow((this.tTrop - deltaT) / ISAT0, f3)
  }

  public getAirData(hp: number): AirData {
    let temperature: number
    let pressure: number

    if (hp < HPtrop) {
      temperature = this.t0 + BetaT * hp
      pressure = ISAP0 * Math.pow(temperature / ISAT0, f3)
    } else {
      temperature = this.tTrop
      pressure = this.pTrop * Math.exp((g0dR / ISATTrop) * (HPtrop - hp))
    }
    const density = pressure / R / temperature
    const soundSpeed = Math.sqrt(kr * temperature)
    return new AirData(hp, pressure, temperature, density, soundSpeed)
  }

  public TAS2Mach(alt: number, tas: number): number {
    return this.getAirData(alt).TAS2Mach(tas)
  }

  public mach2TAS(alt: number, m: number): number {
    return this.getAirData(alt).mach2TAS(m)
  }

  public CAS2TAS(alt: number, cas: number): number {
    return this.getAirData(alt).CAS2TAS(cas)
  }

  public TAS2CAS(alt: number, tas: number): number {
    return this.getAirData(alt).TAS2CAS(tas)
  }

  public mach2CAS(alt: number, m: number): number {
    return this.getAirData(alt).mach2CAS(m)
  }

  public CAS2Mach(alt: number, cas: number): number {
    return this.getAirData(alt).CAS2Mach(cas)
  }
}

export const ISA = new AtmosphereModel(0, 0)

// TAS2Mach TAS -> mach
function _TAS2Mach(tas: number, soundSpeed: number): number {
  return tas / soundSpeed
}
// Mach2TAS  mach -> TAS
function _mach2TAS(mach: number, soundSpeed: number): number {
  return mach * soundSpeed
}

// CAS2TAS CAS->TAS
function _CAS2TAS(cas: number, p: number, rho: number): number {
  let tmp = 1 + (u * ISARho0 * cas * cas) / 2.0 / ISAP0
  tmp = Math.pow(tmp, u1)
  tmp = 1 + (ISAP0 * (tmp - 1)) / p
  tmp = Math.pow(tmp, u) - 1
  tmp = (2.0 * p * tmp) / u / rho
  return Math.sqrt(tmp)
}

function _TAS2CAS(tas: number, p: number, rho: number): number {
  let tmp = 1 + (u * rho * tas * tas) / 2.0 / p
  tmp = Math.pow(tmp, u1)
  tmp = 1 + (p * (tmp - 1)) / ISAP0
  tmp = Math.pow(tmp, u) - 1
  tmp = (2.0 * ISAP0 * tmp) / u / ISARho0
  return Math.sqrt(tmp)
}
